﻿using System;
using System.Net;
using System.Windows;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO.IsolatedStorage;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Xml;
using System.Security;

namespace RSSReader
{
  public class SaveData
  {
    public class FeedInformation
    {
      public string Title { get; set; }
      public string Url { get; set; }
      public int NewCount { get; set; }

      public FeedInformation(string title, string url, int count = 0)
      {
        Title = title;
        Url = url;
        NewCount = count;
      }
    }

    public class FeedItem
    {
      public string Title { get; set; }
      public string Body { get; set; }
      public string URL { get; set; }
      public DateTime Time { get; set; }

      public FeedItem(string title="", string body="", string url="", DateTime time=new DateTime())
      {
        Title = title;
        Body = body;
        URL = url;
        Time = time;
      }
    }

    private IsolatedStorageSettings mSettings;
    private IsolatedStorageFile mStorage;
    private const string UserNameName = "usrn";
    private const string PasswordName = "pswd";
    private const string SortFeedsName = "sort";
    private const string AlphaFeedsName = "alph";
    private const string UnreadOnStartupName = "uros";
    private const string OnlyGetUnreadFeedsName = "unrd";
    private const string FeedsToDownloadName = "ftdl";
    private const string FeedListFile = "Feeds.xml";

    public string UserName
    {
      get
      {
        return getProtectedValueOrDefault<string>(UserNameName, "");
      }

      set
      {
        addProtectedValue(UserNameName, value);
        save();
      }
    }

    public string Password
    {
      get
      {
        return getProtectedValueOrDefault<string>(PasswordName, "");
      }

      set
      {
        addProtectedValue(PasswordName, value);
        save();
      }
    }

    public bool SortFeeds
    {
      get
      {
        return getValueOrDefault(SortFeedsName, false);
      }

      set
      {
        addValue(SortFeedsName, value);
        save();
      }
    }

    public bool AlphaFeeds
    {
      get
      {
        return getValueOrDefault(AlphaFeedsName, false);
      }

      set
      {
        addValue(AlphaFeedsName, value);
        save();
      }
    }

    public bool UnreadOnStartup
    {
      get
      {
        return getValueOrDefault(UnreadOnStartupName, false);
      }

      set
      {
        addValue(UnreadOnStartupName, value);
        save();
      }
    }

    public bool OnlyGetUnreadFeeds
    {
      get 
      {
        return getValueOrDefault(OnlyGetUnreadFeedsName, false);
      }

      set
      {
        addValue(OnlyGetUnreadFeedsName, value);
        save();
      }
    }

    public int FeedsToDownload
    {
      get
      {
        return getValueOrDefault(FeedsToDownloadName, 10);
      }

      set
      {
        addValue(FeedsToDownloadName, value);
        save();
      }
    }

    public Dictionary<string, FeedInformation> Feeds { get; private set; }
    public Dictionary<string, List<FeedItem>> SavedFeedItems { get; private set; }

    public SaveData()
    {
      try
      {
        mSettings = IsolatedStorageSettings.ApplicationSettings;
        mStorage = IsolatedStorageFile.GetUserStoreForApplication();
        Feeds = new Dictionary<string, FeedInformation>();
        SavedFeedItems = new Dictionary<string, List<FeedItem>>();
        loadFeeds();
        loadFeedItems();
      }
      catch (Exception e)
      {
        Debug.WriteLine("Exception with IsolatedStorageSettings.ApplicationSettings: " + e.ToString());
      }
    }

    private void save()
    {
      mSettings.Save();
    }

    private void saveFeeds()
    {
      using (IsolatedStorageFileStream feed = mStorage.OpenFile(FeedListFile, FileMode.OpenOrCreate))
      {
        using (XmlWriter writer = XmlWriter.Create(feed))
        {
          writer.WriteStartElement("Feeds");
          foreach (KeyValuePair<string, FeedInformation> f in Feeds)
          {
            writer.WriteStartElement("Feed");
              writer.WriteAttributeString("title", f.Value.Title);
              writer.WriteAttributeString("url", f.Value.Url);
              writer.WriteAttributeString("count", Convert.ToString(f.Value.NewCount));
            writer.WriteEndElement(); // Feed close
          }
          writer.WriteEndElement(); // Feeds close
          writer.Close();
        }
        feed.Close();
      }
    }

    public void loadFeeds()
    {
      if (mStorage.FileExists(FeedListFile))
      {
        using (IsolatedStorageFileStream feed = mStorage.OpenFile(FeedListFile, FileMode.Open))
        {
          using (XmlReader reader = XmlReader.Create(feed))
          {
            while (reader.ReadToFollowing("Feed"))
            {
              FeedInformation f = new FeedInformation(reader["title"], reader["url"], Convert.ToInt32(reader["count"]));
              addFeed(f, false);
            }
            reader.Close();
          }
          feed.Close();
        }
      }
    }

    public void saveFeedItems(string feed)
    {
      if (SavedFeedItems.ContainsKey(feed))
      {
        using (IsolatedStorageFileStream list = mStorage.OpenFile(feed + ".xml", FileMode.OpenOrCreate))
        {
          using (XmlWriter writer = XmlWriter.Create(list))
          {
            writer.WriteStartElement("Items");
            foreach (FeedItem item in SavedFeedItems[feed])
            {
              writer.WriteStartElement("Item");
              writer.WriteAttributeString("title", item.Title);
              writer.WriteAttributeString("body", item.Body);
              writer.WriteAttributeString("url", item.URL);
              writer.WriteEndElement();
            }
            writer.WriteEndElement();
            writer.Close();
          }
          list.Close();
        }
      }
    }

    public void addFeedItems(string feed, List<FeedItem> items, bool save = true)
    {
      if (!SavedFeedItems.ContainsKey(feed))
      {
        SavedFeedItems[feed] = items;
        if (save) saveFeedItems(feed);
      }
    }

    public void updateFeedItems(string feed, List<FeedItem> items, bool save = true)
    {
      SavedFeedItems[feed] = items;
      if (save) saveFeedItems(feed);
    }

    public void loadFeedItems()
    {
      foreach (KeyValuePair<string, FeedInformation> feed in Feeds)
      {
        string fn = feed.Value.Title + ".xml";
        SavedFeedItems.Add(feed.Value.Title, new List<FeedItem>());
        if (mStorage.FileExists(fn))
        {
          using (IsolatedStorageFileStream file = mStorage.OpenFile(fn, FileMode.Open))
          {
            using (XmlReader reader = XmlReader.Create(file))
            {
              while (reader.ReadToFollowing("Item"))
              {
                FeedItem item = new FeedItem(reader["title"], reader["body"], reader["url"]);
                SavedFeedItems[feed.Value.Title].Add(item);
              }
            }
          }
        }
      }
    }

    public FeedInformation getFeedFromUrl(string url)
    {
      foreach (KeyValuePair<string, FeedInformation> f in Feeds)
        if (f.Value.Url.Equals(url))
          return f.Value;
      return null;
    }

    public bool addFeed(FeedInformation feed, bool save = true)
    {
      if (!Feeds.ContainsKey(feed.Title))
      {
        Feeds[feed.Title] = feed;
        if (save) saveFeeds();
        return true;
      }
      return false;
    }

    public void updateFeed(FeedInformation feed, bool save = true)
    {
      Feeds[feed.Title] = feed;
      if (save) saveFeeds();
    }

    public bool removeFeed(FeedInformation feed, bool save = true)
    {
      bool removed = Feeds.Remove(feed.Title);
      if (save) saveFeeds();
      return removed;
    }

    protected bool addValue(string key, Object value)
    {
      bool valueChanged = false;
      if (mSettings.Contains(key))
      {
        if (mSettings[key] != value)
        {
          mSettings[key] = value;
          valueChanged = true;
        }
      }
      else
      {
        mSettings.Add(key, value);
        valueChanged = true;
      }
      return valueChanged;
    }

    protected bool addProtectedValue(string key, Object value)
    {
      byte[] protectedBytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(value.ToString()), null);
      return addValue(key, protectedBytes);
    }

    protected valueType getValueOrDefault<valueType>(string key, valueType defaultValue)
    {
      valueType value = defaultValue;
      if (mSettings.Contains(key))
      {
        value = (valueType)mSettings[key];
      }
      return value;
    }

    protected valueType getProtectedValueOrDefault<valueType>(string key, valueType defaultValue)
    {
      valueType value = defaultValue;
      if (mSettings.Contains(key) && (mSettings[key] is byte[]))
      {
        byte[] bytes = mSettings[key] as byte[];
        byte[] unprotectedBytes = ProtectedData.Unprotect(bytes, null);
        Object o = (Encoding.UTF8.GetString(unprotectedBytes, 0, unprotectedBytes.Length));
        value = (valueType)(o);
      }
      return value;
    }
  }
}
